import { lazyReportCache } from '../utils/report.js'
import {onAfterLoad, isSupportPerformanceObserver} from '../utils/common.js'

// safari 浏览器
const isSafari = /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent)
// 不统计以下类型的资源。xhr、fetch：单独统计。beacon：用于上报数据,不统计。
const preventList = ['fetch', 'xmlhttprequest', 'beacon']
// safari 会把接口请求当成 other
if (isSafari) preventList.push('other')
function isCache(entry) {
    // 直接从缓存读取或 304
    return entry.transferSize === 0 || (entry.transferSize !== 0 && entry.encodedBodySize === 0)
}
/**
 * 资源加载时间、导航加载时间。这些性能条目提供了关于页面加载过程的详细信息，包括从用户发起请求到页面完全加载的各个阶段的时间点。。
 * DOMContentLoaded 事件，监听性能数据。
 * onload事件，监听性能数据。随后卸载监听。
 * */
export default function observeEntries() {
    onAfterLoad(() => {
        // 资源加载时间
        observeEvent('resource')
        // 导航时间
        observeEvent('navigation')
    })
}

let hasAlreadyCollected = false // 是否已收集
function observeEvent(entryType) {
    function entryHandler(list) {
        const data = list.getEntries ? list.getEntries() : list
        for (const entry of data) {
            if (entryType === 'navigation') {
                // 避免重复收集，防止重复上报
                if (hasAlreadyCollected) return
                if (observer) {
                    observer.disconnect()
                }
                hasAlreadyCollected = true
            }
            if ((!entry.nextHopProtocol && entryType !== 'navigation') ||
                preventList.includes(entry.initiatorType)) {
                return
            }
            const data = {
                type: 'performance',
                subType: entryType,
                startTime: performance.now(),
                name: entry.name, // 资源名称
                sourceType: entry.initiatorType, // 资源类型
                duration: entry.duration, // 资源加载耗时
                dns: entry.domainLookupEnd - entry.domainLookupStart, // DNS 耗时
                tcp: entry.connectEnd - entry.connectStart, // 建立 tcp 连接耗时
                redirect: entry.redirectEnd - entry.redirectStart, // 重定向耗时
                ttfb: entry.responseStart, // 首字节时间
                protocol: entry.nextHopProtocol, // 请求协议
                responseBodySize: entry.encodedBodySize, // 响应内容大小
                responseHeaderSize: entry.transferSize - entry.encodedBodySize, // 响应头部大小
                resourceSize: entry.decodedBodySize, // 资源解压后的大小
                isCache: isCache(entry), // 是否命中缓存
            }
            lazyReportCache(data)
        }
    }
    let observer
    if (isSupportPerformanceObserver()) {
        observer = new PerformanceObserver(entryHandler)
        /**
         * 1、在页面加载过程中已经有很多性能条目。
         * 2、buffered:false，PerformanceObserver只会处理在调用observe方法之后发生的性能条目，而不会处理步骤【1】中的这些条目。
         * 3.1、buffered:true，步骤【1】产生的这些条目会被一次性发送给 entryHandler函数。
         * 3.2、PerformanceObserver被创建后，立即调用 observe 方法开始监听性能条目。执行observe 方法时，会在立即触发一次 entryHandler 函数，以处理所有已经存在的性能条目。
         * */
        observer.observe({type: entryType, buffered: true})
    } else {
        const data = window.performance.getEntriesByType(entryType)
        entryHandler(data)
    }
}
